import requests
import jsonpath
import json
from testapp.dataio.dataiofactory import DataIOFactory
# import sys
# sys.setrecursionlimit(100)



class GetSwagerApi(object):

    def __init__(self):
        self.datafac = DataIOFactory()
        pass


    def initData(self, url):
        """
        取得api-doc
        """
        try:
            # url = 'http://172.56.75.2:9000/apig/sys/v2/api-docs'
            result = requests.get(url=url)
            resJson = result.json()
            self.basePath = resJson['basePath'].rstrip('/')
            try:
                self.cate = resJson['tags']
            except Exception:
                self.cate = []
            self.apiPath = resJson['paths']
            self.resbodyData = resJson['definitions']
        except Exception as e:
            return False, str(e)
        return True, "成功"



    def getData(self, Key, oldKey=None):
        """
        递归整理body,response
        oldKey：防止无尽递归
        """
        data = self.resbodyData[Key]
        if data['type'] == 'array':
            resData = []
            """
            resData[0]['key'] = 'value'
            """
        elif data['type'] == 'object':
            resData = {}
            """
            resData['key'] = 'vaule'
            """
        properties = data['properties']
        for k, v in properties.items():
            if data['type'] == 'array':
                if v.__contains__('type'):
                    if v['type'] == 'string':
                        resData[0][k] = v['type']
                    elif v['type'] == 'integer':
                        resData[0][k] = 0
                    elif v['type'] == 'array':
                        if v['items'].__contains__('type'):
                            resData[0][k] = [0]
                        else:
                            vkey = str(v['items']['$ref']).replace('#/definitions/', '')
                            if vkey == Key or vkey == oldKey:     #防止无限嵌套递归
                                resData[0][k] = []
                            else:
                                resData[0][k] = [self.getData(vkey, Key)]
                elif v.__contains__('$ref'):
                    vkey = str(v['$ref']).replace('#/definitions/', '')
                    if vkey == Key or vkey == oldKey:  # 防止无限嵌套递归
                        resData[0][k] = []
                    else:
                        resData[0][k] = self.getData(vkey, Key)
            if data['type'] == 'object':
                if v.__contains__('type'):
                    if v['type'] == 'string':
                        resData[k] = v['type']
                    elif v['type'] == 'integer':
                        resData[k] = 0
                    elif v['type'] == 'array':
                        if v['items'].__contains__('type'):
                            resData[k] = [0]
                        else:
                            vkey = str(v['items']['$ref']).replace('#/definitions/', '')
                            if vkey == Key or vkey == oldKey:     #防止无限嵌套递归
                                resData[k] = []
                            else:
                                resData[k] = [self.getData(vkey, Key)]
                elif v.__contains__('$ref'):
                    vkey = str(v['$ref']).replace('#/definitions/', '')
                    if vkey == Key or vkey == oldKey:   #防止无限嵌套递归
                        resData[k] = []
                    else:
                        resData[k] = [self.getData(vkey, Key)]
        return resData


    def getApis(self, url):
        """
        格式化接口字段
        """
        isOK, result = self.initData(url)
        if isOK:
            try:
                data = []
                apidocs = []
                for k, v in self.apiPath.items():
                    for ik, iv in v.items():
                        apidoc = {}
                        apidoc['api'] = str(k).replace('{version}', '{}')
                        apidoc['apimethod'] = ik.upper()
                        try:
                            apidoc['name'] = (str(iv['summary']).split('作者'))[0].rstrip(' ').replace('\r', '').replace(
                                '\n', '').split('日期')[0].rstrip(' ')
                        except:
                            apidoc['name'] = str(k)
                        try:
                            apidoc['api'] = self.basePath + apidoc['api'].replace('{}', iv['parameters'][0][
                                'default']).replace('{', '${')
                        except:
                            apidoc['api'] = (self.basePath + apidoc['api']).replace('{', '${')
                        apidoc['tags'] = iv['tags'][0]
                        ref = '$..$ref'
                        try:  ##取body
                            key = str(jsonpath.jsonpath(iv['parameters'], ref)[0]).replace('#/definitions/', '')
                            try:
                                if iv['parameters'][1]['schema']['type'] == 'array':
                                    apidoc['body'] = [self.formatJson(self.getData(key))]
                            except Exception:
                                apidoc['body'] = self.formatJson(self.getData(key))
                        except Exception:
                            apidoc['body'] = ''
                        try:  ##取response
                            key = str(jsonpath.jsonpath(iv['responses'], ref)[0]).replace('#/definitions/', '')
                            apidoc['response'] = self.formatJson(self.getData(key))
                        except Exception:
                            apidoc['response'] = {}
                        apidocs.append(apidoc)
                data.append(self.getApiCate(apidocs))
                data.append(apidocs)
            except Exception as e:
                return False, str(e)
            return True, data
        else:
            return isOK, result
        return True, apidocs

    def getApiCate(self, apidocs):
        if len(self.cate) == 0:
            for apidoc in apidocs:
                tag = {}
                tag['name'] = apidoc['tags']
                if len(self.cate) == 0:
                    self.cate.append(tag)
                else:
                    arr = jsonpath.jsonpath(self.cate, '$..name')
                    if tag['name'] not in arr:
                        self.cate.append(tag)
        return self.cate

    def formatJson(self, dic):
        """
        格式化json串
        """
        if 'dict' in str(type(dic)) and dic != '{}':
            response = json.dumps(dic, sort_keys=False, indent=3, separators=(',', ': '))
            return response
        elif str(dic) == '{}':
            response = json.dumps(dic, sort_keys=False, indent=3, separators=(',', ': '))
            return response
        else:
            return dic

# url = 'http://172.56.75.2:9000/apig/sys/v2/api-docs'
# obj = GetSwagerApi()
# obj.initData(url)
# print(obj.getApis())
# # print(obj.getApiCate()).


    def getSwaggerIntoDatabase(self, url, name):
        """
        获取url swagger中的api-doc放到数据库，取名为 name(Swagger)
        """
        # 判断有没有cat目录，通过name(Swagger),有则取，无则建
        # 判断是cats是否都存在，有则取，无则建
        # 通过接口名称 + 请求方式是否存在，有则取，无则通过api + 请求方式，判断接口是否存在，有则取，无则建
        # 将取出来的接口，都与swagger的数据判断，无更新过，有更新，保存原有数据，更新现有数据
        # 新增的数据添加new标识，更新的字段添加update标识，new\updata\old
        isOK, result = self.getApis(url)
        if isOK is False:
            return isOK, result
        cats = result[0]
        apidoc = result[1]

        catName = name + '(Swagger)'
        isOK, result = self.datafac.getCatebyName(catName)
        if isOK:
            g_id = result['id']
            isOK, result = self.datafac.getCateByparentId(g_id)
            if isOK and len(result) > 0:
                return self.upApidata(apidoc, cats, result)
            elif isOK:
                isOK, result = self.insetLastcat(cats, g_id)
                if isOK:
                    return self.insertApiData(result, apidoc)
                else:
                    return isOK, result
        else:
            #插入根目录
            isOK, result = self.insetTopcat(catName)
            if isOK:
                isOK, result = self.insetLastcat(cats, result.id)
                if isOK:
                    return self.insertApiData(result, apidoc)
                else:
                    return isOK, result
            else:
                return isOK, result


    def upApidata(self, apidocs, cats, oldcats):
        """
        更新用例数据
        #通过接口名称 + 请求方式是否存在，有则取，无则通过api + 请求方式，判断接口是否存在，有则取，无则建
        #将取出来的接口，都与swagger的数据判断，无更新过，有更新，保存原有数据，更新现有数据
        """
        isOK, result = self.upApiCats(cats, oldcats)
        if isOK:
            cats = result
            newapi = []
            for data in apidocs:
                isOK, result = self.datafac.getApidatabySomepar(data)
                if isOK and len(result) > 0:
                    if self.judgeApidata(data, result[0]):
                        print('更新')
                        self.datafac.upApidataSaveold(data, result[0])
                elif isOK:
                    newapi.append(data)
                else:
                    return isOK, result
            if len(newapi) > 0:
                self.insertApiData(cats, newapi)
        else:
            return isOK, result
        return isOK, '更新数据成功'

    def judgeApidata(self, nData, oData):
        """
        判断api数据是否存在并没有变更
        """
        for key, value in nData.items():
            if key != 'tags':
                if (key == 'body' or key == 'response') and value != '':
                    if 'list' in str(type(value)):
                        new = json.loads(value[0])
                        try:
                            old =eval(oData[key].replace("'", '').replace('\\n', '\n'))[0]
                        except Exception:
                            old = json.loads(oData[key])
                    elif json.dumps(value) in '{}':
                        if json.dumps(value) not in oData[key]:
                            return True
                        else:
                            return False
                    else:
                        new = json.loads(value)
                        old = json.loads(oData[key])
                    if new.items() != old.items():
                        return True
                elif oData[key] != value:
                    return True
        return False

    def upApiCats(self, cats, oldcats):
        """
        更新cats目录
        """
        ncats = []
        topCatid = jsonpath.jsonpath(oldcats, '$..parentid')[0]
        oldcasName = jsonpath.jsonpath(oldcats, '$..name')
        for cat in cats:
            if cat['name'] not in oldcasName:
                ncats.append(cat)
        if len(ncats) > 0:
            self.insetLastcat(ncats, topCatid)
            return self.datafac.getCateByparentId(topCatid)
        return True, oldcats


    def insetTopcat(self, catName):
        """
        插入topCate
        """
        data = {}
        data['name'] = catName
        data['parentid'] = 1
        data['level'] = 2
        return self.datafac.insertApiCat(data)

    def insetLastcat(self, cats, topCatid):
        """
        插入cats
        """
        obj_cats = []
        for cat in cats:
            data = {}
            data['name'] = cat['name']
            data['parentid'] = topCatid
            data['level'] = 3
            isOK, result = self.datafac.insertApiCat(data)
            if isOK:
                obj_cats.append(result)
        return True, obj_cats

    def insertApiData(self, cats, apidoc):
        """
        插入api数据
        """
        for api in apidoc:
            for cat in cats:
                try:
                    name = cat.name
                except Exception:
                    name = cat['name']
                if name == api['tags']:
                    try:
                        catid = cat.id
                    except:
                        catid = cat['id']
                    api['catid_id'] = catid
                    api['headers'] = ''
                    self.datafac.insertApi(api)
                    break
        return True, "插入数据成功"